package com.wanxing.sellerapp.seller;

import com.blankj.utilcode.util.SPUtils;
import com.wanxing.sellerapp.seller.entity.ScaleWeight;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 门
 */
public class Door {

    public interface Callback{
        void onChange(int doorNo, List<ScaleWeight> weights);
        void onScaleError(int doorNo, boolean valueError, boolean weightError, int scaleNo, long errorId);
    }

    public static final String SP_DATA_LOCKED = "locked";

    public static final String SP_DATA_ORDER_STATE = "orderState";

    //开门后，开启订单。该状态将给服务器推送重量变化数据
    public static final int ORDER_STATE_OPEN = 1;

    //关门后，取稳定重量值。该状态程序需要确定一个最终变化重量，作为订单最终重量值
    public static final int ORDER_STATE_SETTLE = 2;

    //空闲（无订单）。发送最终重量后将该门标为空闲状态。 此时只检测称是否正常
    public static final int ORDER_STATE_FREE = 3;

    private Callback mCallback;

    /**
     * 门编号
     */
    private final int no;

    /**
     * 门内包含的秤
     */
    private final List<Scale> mScales;
    private final Map<Integer, Scale> scaleMap = new HashMap<>();



    public Door(int no, List<Scale> scales) {
        this.no = no;
        this.mScales = scales;
        for (Scale scale : scales) {
            scaleMap.put(scale.getScaleNo(), scale);
            scale.setErrorCallback((valueError, weightError, scaleNo, errorId) -> {
                mCallback.onScaleError(no, valueError, weightError, scaleNo, errorId);
            });
            scale.setOnWeightChangeCallback((scaleNo, weight) -> {
                //忽略关门状态的重量变化
                if (!mLocked.get()){
                    mCallback.onChange(
                            no,
                            mScales.stream()
                                    .map(s -> new ScaleWeight(s.getScaleNo(), s.getCurrentWeight()))
                                    .collect(Collectors.toList())
                    );
                }
            });
        }
        loadStateFromDisk();
    }

    /**
     * 锁是否关闭
     */
    private final AtomicBoolean mLocked = new AtomicBoolean(true);

    /**
     * 订单状态
     */
    private final AtomicInteger mOrderState = new AtomicInteger(ORDER_STATE_FREE);

    private String spFileName(){
        return "door" + no;
    }

    /**
     * 加载设备历史状态
     */
    private void loadStateFromDisk() {
        String name = spFileName();
        SPUtils disk = SPUtils.getInstance(name);
        setLockState(disk.getBoolean(SP_DATA_LOCKED, true));
        mOrderState.set(disk.getInt(SP_DATA_ORDER_STATE, ORDER_STATE_FREE));
    }

    /**
     * 设置刚获取到的重量
     */
    public void feedNewWeights(int[] weights) {
        for (Scale scale : mScales) {
            for (int i = 0; i < weights.length; i++) {
                int scaleNo = i + 1;
                if (scaleNo == scale.getScaleNo()) {
                    scale.setNewWeight(weights[i]);
                }
            }
        }
    }

    public void setLockState(boolean locked){
        mLocked.set(locked);
        //上锁后开始检测机器异常
        if (locked){
            for (Scale scale : mScales) {
                scale.setCheckError(true);
            }
        }
    }

    /**
     * @return 关门后稳定的秤重量数据
     */
    public List<ScaleWeight> getEndOrderWeight() throws InterruptedException {
        List<ScaleWeight> weights = new ArrayList<>();
        CountDownLatch countDownLatch = new CountDownLatch(mScales.size());
        for (Scale scale : mScales) {
            scale.getStableWeightDelay((scaleNo, weight) -> {
                weights.add(new ScaleWeight(scaleNo, weight));
                countDownLatch.countDown();
            }, 2000);
        }
        countDownLatch.await();
        return weights;
    }

    public int getNo() {
        return no;
    }

    public List<Scale> getScales() {
        return mScales;
    }

    public Scale getScale(int scaleNo) {
        return scaleMap.get(scaleNo);
    }

    /**
     * @return 实时秤重量数据
     */
    public List<ScaleWeight> getRealTimeWeightData(){
        return  mScales
                .stream()
                .map(scale -> new ScaleWeight(scale.getScaleNo(), scale.getCurrentWeight()))
                .collect(Collectors.toList());
    }

    /**
     * @return 实时秤稳定数据
     */
    public List<ScaleWeight> getCurrentStableWeight(){
        return  mScales
                .stream()
                .map(scale -> new ScaleWeight(scale.getScaleNo(), scale.getStableWeight()))
                .collect(Collectors.toList());
    }

    public void setCallback(Callback callback) {
        this.mCallback = callback;
    }

}
